home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1991
/
10
/
386bsd.101
next >
Wrap
Text File
|
1991-09-10
|
12KB
|
425 lines
_PORTING UNIX TO THE 386: MULTIPROGRAMMING AND MULTITASKING_
by William Frederick Jolitz and Lynne Greer Jolitz
[LISTING ONE]
/* code fragment from i386/trap.c (in trap() and syscall()) */
...
if (want_resched) {
/*
* Enqueue our current running process first, so
* that we may eventually run again. Block clock
* interrupts that may interfere with priority
* (e.g. we'd rather it not be recalculated part
* way thru setrun).
*/
(void) splclock();
setrq(p);
(void) splnone();
p->p_stats->p_ru.ru_nivcsw++;
swtch();
while (i = CURSIG(p))
psig(i);
}
...
[LISTING TWO]
/*-
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*/
/*
* General sleep call.
* Suspends current process until a wakeup is made on chan.
* The process will then be made runnable with priority pri.
* Sleeps at most timo/hz seconds (0 means no timeout).
* If pri includes PCATCH flag, signals are checked
* before and after sleeping, else signals are not checked.
* Returns 0 if awakened, EWOULDBLOCK if the timeout expires.
* If PCATCH is set and a signal needs to be delivered,
* ERESTART is returned if the current system call should be restarted
* if possible, and EINTR is returned if the system call should
* be interrupted by the signal (return EINTR).
*/
tsleep(chan, pri, wmesg, timo)
caddr_t chan;
int pri;
char *wmesg;
int timo;
{
register struct proc *p = curproc;
register struct slpque *qp;
register s;
int sig, catch = pri & PCATCH;
extern int cold;
int endtsleep();
s = splhigh();
if (cold || panicstr) {
/*
* After a panic, or during autoconfiguration,
* just give interrupts a chance, then just return;
* don't run any other procs or panic below,
* in case this is the idle process and already asleep.
*/
splx(safepri);
splx(s);
return (0);
}
#ifdef DIAGNOSTIC
if (chan == 0 || p->p_stat != SRUN || p->p_rlink)
panic("tsleep");
#endif
p->p_wchan = chan;
p->p_wmesg = wmesg;
p->p_slptime = 0;
p->p_pri = pri & PRIMASK;
/* Insert onto the tail of a sleep queue list. */
qp = &slpque[HASH(chan)];
if (qp->sq_head == 0)
qp->sq_head = p;
else
*qp->sq_tailp = p;
*(qp->sq_tailp = &p->p_link) = 0;
/*
* If time limit to sleep, schedule a timeout
*/
if (timo)
timeout(endtsleep, (caddr_t)p, timo);
/* We put ourselves on the sleep queue and start our timeout
* before calling CURSIG, as we could stop there, and a wakeup
* or a SIGCONT (or both) could occur while we were stopped.
* A SIGCONT would cause us to be marked as SSLEEP
* without resuming us, thus we must be ready for sleep
* when CURSIG is called. If the wakeup happens while we're
* stopped, p->p_wchan will be 0 upon return from CURSIG.
*/
if (catch) {
p->p_flag |= SSINTR;
if (sig = CURSIG(p)) {
if (p->p_wchan)
unsleep(p);
p->p_stat = SRUN;
goto resume;
}
if (p->p_wchan == 0) {
catch = 0;
goto resume;
}
}
/* Set process sleeping, go find another process to run */
p->p_stat = SSLEEP;
p->p_stats->p_ru.ru_nvcsw++;
swtch();
resume:
splx(s);
p->p_flag &= ~SSINTR;
/* cleanup timeout case */
if (p->p_flag & STIMO) {
p->p_flag &= ~STIMO;
if (catch == 0 || sig == 0)
return (EWOULDBLOCK);
} else if (timo)
untimeout(endtsleep, (caddr_t)p);
/* if signal was caught, return appropriately */
if (catch && (sig != 0 || (sig = CURSIG(p)))) {
if (p->p_sigacts->ps_sigintr & sigmask(sig))
return (EINTR);
return (ERESTART);
}
return (0);
}
[LISTING THREE]
/*-
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*/
/* Wakeup on "chan"; set all processes
* sleeping on chan to run state.
*/
wakeup(chan)
register caddr_t chan;
{
register struct slpque *qp;
register struct proc *p, **q;
int s;
s = splhigh();
qp = &slpque[HASH(chan)];
restart:
for (q = &qp->sq_head; p = *q; ) {
#ifdef DIAGNOSTIC
if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
panic("wakeup");
#endif
if (p->p_wchan == chan) {
p->p_wchan = 0;
*q = p->p_link;
if (qp->sq_tailp == &p->p_link)
qp->sq_tailp = q;
if (p->p_stat == SSLEEP) {
/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
p->p_stat = SRUN;
if (p->p_flag & SLOAD)
setrq(p);
/*
* Since curpri is a usrpri,
* p->p_pri is always better than curpri.
*/
if ((p->p_flag&SLOAD) == 0)
wakeup((caddr_t)&proc0);
else
need_resched();
/* END INLINE EXPANSION */
goto restart;
}
} else
q = &p->p_link;
}
splx(s);
}
[LISTING FOUR]
/* Copyright (c) 1989, 1990, 1991 William Jolitz. All rights reserved.
* Written by William Jolitz 6/89
*
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* Swtch() */
ENTRY(swtch)
incl _cnt+V_SWTCH
/* switch to new process. first, save context as needed */
movl _curproc, %ecx
movl P_ADDR(%ecx), %ecx
/* unload processor registers, we need to use them */
movl (%esp),%eax
movl %eax, PCB_EIP(%ecx)
movl %ebx, PCB_EBX(%ecx)
movl %esp, PCB_ESP(%ecx)
movl %ebp, PCB_EBP(%ecx)
movl %esi, PCB_ESI(%ecx)
movl %edi, PCB_EDI(%ecx)
/* save system related details */
movl $0,_CMAP2 /* blast temporary map PTE */
movw _cpl, %ax
movw %ax, PCB_IML(%ecx) /* save ipl */
/* save is done, now choose a new process or idle */
rescanfromidle:
movl _whichqs,%edi
2:
bsfl %edi,%eax /* found a full queue? */
jz idle /* if nothing, idle waiting for some */
/* we have a queue with something in it */
btrl %eax,%edi /* clear queue full status */
jnb 2b /* if it was clear, look for another */
movl %eax,%ebx /* save which one we are using */
/* obtain the run queue header */
shll $3,%eax
addl $_qs,%eax
movl %eax,%esi
#ifdef DIAGNOSTIC
/* queue was promised to have a process in it */
cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */
fje panicswtch /* not possible */
#endif
/* unlink from front of process q */
movl P_LINK(%eax),%ecx
movl P_LINK(%ecx),%edx
movl %edx,P_LINK(%eax)
movl P_RLINK(%ecx),%eax
movl %eax,P_RLINK(%edx)
/* is the queue truely empty? */
cmpl P_LINK(%ecx),%esi
je 3f
btsl %ebx,%edi /* nope, set to indicate full */
3:
movl %edi,_whichqs /* update queue status */
/* notify system we've rescheduled */
movl $0,%eax
movl %eax,_want_resched
#ifdef DIAGNOSTIC
/* process was insured to be runnable, not sleeping */
cmpl %eax,P_WCHAN(%ecx)
jne panicswtch
cmpb $ SRUN,P_STAT(%ecx)
jne panicswtch
#endif
/* isolate process from run queues */
movl %eax,P_RLINK(%ecx)
/* record details of newproc in our global variables */
movl %ecx,_curproc
movl P_ADDR(%ecx),%edx
movl %edx,_curpcb
movl PCB_CR3(%edx),%ebx
/* switch address space */
movl %ebx,%cr3
/* restore context */
movl PCB_EBX(%edx), %ebx
movl PCB_ESP(%edx), %esp
movl PCB_EBP(%edx), %ebp
movl PCB_ESI(%edx), %esi
movl PCB_EDI(%edx), %edi
movl PCB_EIP(%edx), %eax
movl %eax, (%esp)
#ifdef NPX
/* npx will interrupt next instruction, delay npx switch till then */
#define CR0_TS 0x08
movl %cr0,%eax
orb $CR0_TS,%al /* disable it */
movl %eax,%cr0
#endif
/* set priority level we were at last time */
pushl PCB_IML(%edx)
call _splx
popl %eax
movl %edx,%eax /* return (1); (actually, non-zero) */
ret
/* When no processes are on the runq, Swtch branches to idle
* to wait for something to come ready.
*/
.globl Idle
Idle:
idle:
call _spl0
cmpl $0,_whichqs
jne rescanfromidle
hlt /* wait for interrupt */
jmp idle
[LISTING FIVE]
/* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 7/91
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* Enqueue a process on a run queue. Process will be on a run queue
* until run for a time slice (swtch()), or removed by remrq().
* Should only be called with a running process, and with the
* processor protecting against rescheduling.
*/
setrq(p) struct proc *p; {
register rqidx;
struct prochd *ph;
struct proc *or;
/* Rescale 256 priority levels to fit into 32 queue headers */
rqidx = p->p_pri / 4;
#ifdef DIAGNOSTIC
/* If this process is already linked on run queue, we're in trouble. */
if (p->p_rlink != 0)
panic("setrq: already linked");
#endif
/* Link this process on the appropriate queue tail */
ph = qs + rqidx;
p->p_link = (struct proc *)ph;
or = p->p_rlink = ph->ph_rlink;
ph->ph_rlink = or->p_link = p;
/* Indicate that this queue has at least one process in it */
whichqs |= (1<<rqidx);
}
/* Dequeue a process from the run queue its stuck on. Must be called
* with rescheduling clock blocked.
*/
remrq(p) struct proc *p; {
register rqidx;
struct prochd *ph;
/* Rescale 256 priority levels to fit into 32 queue headers */
rqidx = p->p_pri / 4;
#ifdef DIAGNOSTIC
/* If a run queue is empty, something is definitely wrong */
if (whichqs & (1<<rqidx) == 0)
panic("remrq");
#endif
/* Unlink process off doublely-linked run queue */
p->p_link->p_rlink = p->p_rlink;
p->p_rlink->p_link = p->p_link;
/* If something is still present on the queue,
* set the corresponding bit. Otherwise clear it.
*/
ph = qs + rqidx;
if (ph->ph_link == ph)
whichqs &= ~(1<<rqidx);
else
whichqs |= (1<<rqidx);
/* Mark this process as unlinked */
p->p_rlink = (struct proc *) 0;
}